package com.example.demo.controller.response;

import java.time.LocalDate;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.context.support.DefaultMessageSourceResolvable;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.annotation.ControllerAdvice;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.context.request.WebRequest;
import org.springframework.web.servlet.mvc.method.annotation.ResponseEntityExceptionHandler;

import com.example.demo.common.ResponseCode;
import com.example.demo.common.exception.BaseException;

@ControllerAdvice
public class ExceptionHandlerAdvice extends ResponseEntityExceptionHandler {

    private static final Logger logger4j = LoggerFactory.getLogger(ExceptionHandlerAdvice.class);

    /**
     * 处理未捕获的RuntimeException
     *
     * @param e
     *            运行时异常
     * @return 统一响应体
     */
    @ExceptionHandler(RuntimeException.class)
    public ResponseEntity<ResponseResult> handleRuntimeException(RuntimeException e) {
        logger4j.error(e.getMessage(), e);
        return ResponseEntity
            .ok(new ResponseResult(ResponseCode.SERVICE_ERROR.getCode(), ResponseCode.SERVICE_ERROR.getMsg(), null));
    }

    @ExceptionHandler(Exception.class)
    protected ResponseEntity<ResponseResult> handleException(Exception e) {
        logger4j.error("api exception.", e);
        return ResponseEntity
            .ok(new ResponseResult(ResponseCode.SERVICE_ERROR.getCode(), ResponseCode.SERVICE_ERROR.getMsg(), null));
    }

    /**
     * 处理业务异常BaseException
     *
     * @param e
     *            业务异常
     * @return 统一响应体
     */
    @ExceptionHandler(BaseException.class)
    public ResponseEntity<ResponseResult> handleBaseException(BaseException e) {
        logger4j.warn("Handle Exception {{}}", e.getCode().getMsg());
        ResponseCode code = e.getCode();
        return ResponseEntity.ok(new ResponseResult(code.getCode(), code.getMsg(), null));

    }

    @Override
    protected ResponseEntity<Object> handleMethodArgumentNotValid(MethodArgumentNotValidException ex,
        HttpHeaders headers, HttpStatus status, WebRequest request) {

        Map<String, Object> body = new LinkedHashMap<>();
        body.put("timestamp", LocalDate.now());
        body.put("status", status.value());

        List<String> errors = ex.getBindingResult().getFieldErrors().stream()
            .map(DefaultMessageSourceResolvable::getDefaultMessage).collect(Collectors.toList());

        body.put("errors", errors);

        return new ResponseEntity<>(body, HttpStatus.BAD_REQUEST);
    }

}
